import JSBI from '../dist/jsbi.mjs';
import {assertTrue} from './assert.mjs';

const intn_data = [
  {expected: '-1', n: 3, x: '15'},
  {expected: '-2', n: 3, x: '14'},
  {expected: '-3', n: 3, x: '13'},
  {expected: '-4', n: 3, x: '12'},
  {expected: '3', n: 3, x: '11'},
  {expected: '2', n: 3, x: '10'},
  {expected: '1', n: 3, x: '9'},
  {expected: '0', n: 3, x: '8'},
  {expected: '-1', n: 3, x: '7'},
  {expected: '-2', n: 3, x: '6'},
  {expected: '-3', n: 3, x: '5'},
  {expected: '-4', n: 3, x: '4'},
  {expected: '3', n: 3, x: '3'},
  {expected: '2', n: 3, x: '2'},
  {expected: '1', n: 3, x: '1'},
  {expected: '0', n: 3, x: '0'},
  {expected: '-1', n: 3, x: '-1'},
  {expected: '-2', n: 3, x: '-2'},
  {expected: '-3', n: 3, x: '-3'},
  {expected: '-4', n: 3, x: '-4'},
  {expected: '3', n: 3, x: '-5'},
  {expected: '2', n: 3, x: '-6'},
  {expected: '1', n: 3, x: '-7'},
  {expected: '0', n: 3, x: '-8'},
  {expected: '-1', n: 3, x: '-9'},
  {expected: '-2', n: 3, x: '-10'},
  {expected: '-3', n: 3, x: '-11'},
  {expected: '-4', n: 3, x: '-12'},
  {expected: '3', n: 3, x: '-13'},
  {expected: '2', n: 3, x: '-14'},
  {expected: '1', n: 3, x: '-15'},

  {expected: '254', n: 10, x: '254'},
  {expected: '255', n: 10, x: '255'},
  {expected: '256', n: 10, x: '256'},
  {expected: '257', n: 10, x: '257'},
  {expected: '510', n: 10, x: '510'},
  {expected: '511', n: 10, x: '511'},
  {expected: '-512', n: 10, x: '512'},
  {expected: '-511', n: 10, x: '513'},
  {expected: '-2', n: 10, x: '1022'},
  {expected: '-1', n: 10, x: '1023'},
  {expected: '0', n: 10, x: '1024'},
  {expected: '1', n: 10, x: '1025'},

  {expected: '-254', n: 10, x: '-254'},
  {expected: '-255', n: 10, x: '-255'},
  {expected: '-256', n: 10, x: '-256'},
  {expected: '-257', n: 10, x: '-257'},
  {expected: '-510', n: 10, x: '-510'},
  {expected: '-511', n: 10, x: '-511'},
  {expected: '-512', n: 10, x: '-512'},
  {expected: '511', n: 10, x: '-513'},
  {expected: '2', n: 10, x: '-1022'},
  {expected: '1', n: 10, x: '-1023'},
  {expected: '0', n: 10, x: '-1024'},
  {expected: '-1', n: 10, x: '-1025'},

  {expected: '0', n: 0, x: '0'},
  {expected: '0', n: 1, x: '0'},
  {expected: '0', n: 16, x: '0'},
  {expected: '0', n: 31, x: '0'},
  {expected: '0', n: 32, x: '0'},
  {expected: '0', n: 33, x: '0'},
  {expected: '0', n: 63, x: '0'},
  {expected: '0', n: 64, x: '0'},
  {expected: '0', n: 65, x: '0'},
  {expected: '0', n: 127, x: '0'},
  {expected: '0', n: 128, x: '0'},
  {expected: '0', n: 129, x: '0'},

  {expected: '0', n: 0, x: '42'},
  {expected: '0', n: 1, x: '42'},
  {expected: '42', n: 16, x: '42'},
  {expected: '42', n: 31, x: '42'},
  {expected: '42', n: 32, x: '42'},
  {expected: '42', n: 33, x: '42'},
  {expected: '42', n: 63, x: '42'},
  {expected: '42', n: 64, x: '42'},
  {expected: '42', n: 65, x: '42'},
  {expected: '42', n: 127, x: '42'},
  {expected: '42', n: 128, x: '42'},
  {expected: '42', n: 129, x: '42'},

  {expected: '0', n: 0, x: '-42'},
  {expected: '0', n: 1, x: '-42'},
  {expected: '-42', n: 16, x: '-42'},
  {expected: '-42', n: 31, x: '-42'},
  {expected: '-42', n: 32, x: '-42'},
  {expected: '-42', n: 33, x: '-42'},
  {expected: '-42', n: 63, x: '-42'},
  {expected: '-42', n: 64, x: '-42'},
  {expected: '-42', n: 65, x: '-42'},
  {expected: '-42', n: 127, x: '-42'},
  {expected: '-42', n: 128, x: '-42'},
  {expected: '-42', n: 129, x: '-42'},

  {expected: '0', n: 0, x: '4294967295'},
  {expected: '-1', n: 1, x: '4294967295'},
  {expected: '-1', n: 16, x: '4294967295'},
  {expected: '-1', n: 31, x: '4294967295'},
  {expected: '-1', n: 32, x: '4294967295'},
  {expected: '4294967295', n: 33, x: '4294967295'},
  {expected: '4294967295', n: 63, x: '4294967295'},
  {expected: '4294967295', n: 64, x: '4294967295'},
  {expected: '4294967295', n: 65, x: '4294967295'},
  {expected: '4294967295', n: 127, x: '4294967295'},
  {expected: '4294967295', n: 128, x: '4294967295'},
  {expected: '4294967295', n: 129, x: '4294967295'},

  {expected: '0', n: 0, x: '-4294967295'},
  {expected: '-1', n: 1, x: '-4294967295'},
  {expected: '1', n: 16, x: '-4294967295'},
  {expected: '1', n: 31, x: '-4294967295'},
  {expected: '1', n: 32, x: '-4294967295'},
  {expected: '-4294967295', n: 33, x: '-4294967295'},
  {expected: '-4294967295', n: 63, x: '-4294967295'},
  {expected: '-4294967295', n: 64, x: '-4294967295'},
  {expected: '-4294967295', n: 65, x: '-4294967295'},
  {expected: '-4294967295', n: 127, x: '-4294967295'},
  {expected: '-4294967295', n: 128, x: '-4294967295'},
  {expected: '-4294967295', n: 129, x: '-4294967295'},

  {expected: '42', n: 2**32, x: '42'},
  {expected: '4294967295', n: 2**32, x: '4294967295'},
  {expected: '4294967296', n: 2**32, x: '4294967296'},
  {expected: '4294967297', n: 2**32, x: '4294967297'},

  {expected: '0', n: {}, x: '12'},
  {expected: '0', n: 2.9999, x: '12'},
  {expected: '-4', n: 3.1234, x: '12'},

  {expected: '-4', n: 3, x: '12'},
  {expected: '0x123456789abcdef', n: 64, x: '0xabcdef0123456789abcdef'},

  // Regression test for crbug.com/v8/8426.
  {expected: '-0x8000000000000000', n: 64, x: '-0x8000000000000000'},
];

const uintn_data = [
  {expected: '7', n: 3, x: '15'},
  {expected: '6', n: 3, x: '14'},
  {expected: '5', n: 3, x: '13'},
  {expected: '4', n: 3, x: '12'},
  {expected: '3', n: 3, x: '11'},
  {expected: '2', n: 3, x: '10'},
  {expected: '1', n: 3, x: '9'},
  {expected: '0', n: 3, x: '8'},
  {expected: '7', n: 3, x: '7'},
  {expected: '6', n: 3, x: '6'},
  {expected: '5', n: 3, x: '5'},
  {expected: '4', n: 3, x: '4'},
  {expected: '3', n: 3, x: '3'},
  {expected: '2', n: 3, x: '2'},
  {expected: '1', n: 3, x: '1'},
  {expected: '0', n: 3, x: '0'},
  {expected: '7', n: 3, x: '-1'},
  {expected: '6', n: 3, x: '-2'},
  {expected: '5', n: 3, x: '-3'},
  {expected: '4', n: 3, x: '-4'},
  {expected: '3', n: 3, x: '-5'},
  {expected: '2', n: 3, x: '-6'},
  {expected: '1', n: 3, x: '-7'},
  {expected: '0', n: 3, x: '-8'},
  {expected: '7', n: 3, x: '-9'},
  {expected: '6', n: 3, x: '-10'},
  {expected: '5', n: 3, x: '-11'},
  {expected: '4', n: 3, x: '-12'},
  {expected: '3', n: 3, x: '-13'},
  {expected: '2', n: 3, x: '-14'},
  {expected: '1', n: 3, x: '-15'},

  {expected: '254', n: 10, x: '254'},
  {expected: '255', n: 10, x: '255'},
  {expected: '256', n: 10, x: '256'},
  {expected: '257', n: 10, x: '257'},
  {expected: '510', n: 10, x: '510'},
  {expected: '511', n: 10, x: '511'},
  {expected: '512', n: 10, x: '512'},
  {expected: '513', n: 10, x: '513'},
  {expected: '1022', n: 10, x: '1022'},
  {expected: '1023', n: 10, x: '1023'},
  {expected: '0', n: 10, x: '1024'},
  {expected: '1', n: 10, x: '1025'},

  {expected: '770', n: 10, x: '-254'},
  {expected: '769', n: 10, x: '-255'},
  {expected: '768', n: 10, x: '-256'},
  {expected: '767', n: 10, x: '-257'},
  {expected: '514', n: 10, x: '-510'},
  {expected: '513', n: 10, x: '-511'},
  {expected: '512', n: 10, x: '-512'},
  {expected: '511', n: 10, x: '-513'},
  {expected: '2', n: 10, x: '-1022'},
  {expected: '1', n: 10, x: '-1023'},
  {expected: '0', n: 10, x: '-1024'},
  {expected: '1023', n: 10, x: '-1025'},

  {expected: '0', n: 0, x: '0'},
  {expected: '0', n: 1, x: '0'},
  {expected: '0', n: 16, x: '0'},
  {expected: '0', n: 31, x: '0'},
  {expected: '0', n: 32, x: '0'},
  {expected: '0', n: 33, x: '0'},
  {expected: '0', n: 63, x: '0'},
  {expected: '0', n: 64, x: '0'},
  {expected: '0', n: 65, x: '0'},
  {expected: '0', n: 127, x: '0'},
  {expected: '0', n: 128, x: '0'},
  {expected: '0', n: 129, x: '0'},

  {expected: '0', n: 0, x: '42'},
  {expected: '0', n: 1, x: '42'},
  {expected: '42', n: 16, x: '42'},
  {expected: '42', n: 31, x: '42'},
  {expected: '42', n: 32, x: '42'},
  {expected: '42', n: 33, x: '42'},
  {expected: '42', n: 63, x: '42'},
  {expected: '42', n: 64, x: '42'},
  {expected: '42', n: 65, x: '42'},
  {expected: '42', n: 127, x: '42'},
  {expected: '42', n: 128, x: '42'},
  {expected: '42', n: 129, x: '42'},

  {expected: '0', n: 0, x: '-42'},
  {expected: '0', n: 1, x: '-42'},
  {expected: '65494', n: 16, x: '-42'},
  {expected: '2147483606', n: 31, x: '-42'},
  {expected: '4294967254', n: 32, x: '-42'},
  {expected: '8589934550', n: 33, x: '-42'},
  {expected: '9223372036854775766', n: 63, x: '-42'},
  {expected: '18446744073709551574', n: 64, x: '-42'},
  {expected: '36893488147419103190', n: 65, x: '-42'},
  {expected: '170141183460469231731687303715884105686', n: 127, x: '-42'},
  {expected: '340282366920938463463374607431768211414', n: 128, x: '-42'},
  {expected: '680564733841876926926749214863536422870', n: 129, x: '-42'},

  {expected: '0', n: 0, x: '4294967295'},
  {expected: '1', n: 1, x: '4294967295'},
  {expected: '65535', n: 16, x: '4294967295'},
  {expected: '2147483647', n: 31, x: '4294967295'},
  {expected: '4294967295', n: 32, x: '4294967295'},
  {expected: '4294967295', n: 33, x: '4294967295'},
  {expected: '4294967295', n: 63, x: '4294967295'},
  {expected: '4294967295', n: 64, x: '4294967295'},
  {expected: '4294967295', n: 65, x: '4294967295'},
  {expected: '4294967295', n: 127, x: '4294967295'},
  {expected: '4294967295', n: 128, x: '4294967295'},
  {expected: '4294967295', n: 129, x: '4294967295'},

  {expected: '0', n: 0, x: '-4294967295'},
  {expected: '1', n: 1, x: '-4294967295'},
  {expected: '1', n: 16, x: '-4294967295'},
  {expected: '1', n: 31, x: '-4294967295'},
  {expected: '1', n: 32, x: '-4294967295'},
  {expected: '4294967297', n: 33, x: '-4294967295'},
  {expected: '9223372032559808513', n: 63, x: '-4294967295'},
  {expected: '18446744069414584321', n: 64, x: '-4294967295'},
  {expected: '36893488143124135937', n: 65, x: '-4294967295'},
  {expected: '170141183460469231731687303711589138433', n: 127, x: '-4294967295'},
  {expected: '340282366920938463463374607427473244161', n: 128, x: '-4294967295'},
  {expected: '680564733841876926926749214859241455617', n: 129, x: '-4294967295'},

  {expected: '42', n: 2**32, x: '42'},
  {expected: '4294967295', n: 2**32, x: '4294967295'},
  {expected: '4294967296', n: 2**32, x: '4294967296'},
  {expected: '4294967297', n: 2**32, x: '4294967297'},

  {expected: '0x7234567812345678', n: 63, x: '0xf234567812345678'},

  {expected: '0', n: {}, x: '12'},
  {expected: '0', n: 2.9999, x: '12'},
  {expected: '4', n: 3.1234, x: '12'},

  {expected: '4', n: 3, x: '12'},

  // crbug.com/936506
  {expected: '1', n: 15, x: '0x100000001'},
  {expected: '1', n: 15, x: '0x10000000000000001'},
];

function parse(string) {
  if (string.charCodeAt(0) === 0x2D) { // '-'
    return JSBI.unaryMinus(JSBI.BigInt(string.slice(1)));
  }
  return JSBI.BigInt(string);
}

for (const test of intn_data) {
  const x = parse(test.x);
  const expected = parse(test.expected);
  const result = JSBI.asIntN(test.n, x);
  assertTrue(JSBI.equal(expected, result),
      `Unexpected result for asIntN(${test.n}, ${ test.x }):
    Expected: ${ test.expected }
    Actual:   ${ result.toString() }`.trim());
}

for (const test of uintn_data) {
  const x = parse(test.x);
  const expected = parse(test.expected);
  const result = JSBI.asUintN(test.n, x);
  assertTrue(JSBI.equal(expected, result),
      `Unexpected result for asUintN(${test.n}, ${ test.x }):
    Expected: ${ test.expected }
    Actual:   ${ result.toString() }`.trim());
}
